﻿using Microsoft.EntityFrameworkCore;
using System.Linq.Expressions;

namespace Tpl.Domain.Repository
{
    public interface IAsyncRepository<TEntity, TKey> where TEntity : class
    {
        // query
        IQueryable<TEntity> All();
        IQueryable<TEntity> All(string[] propertiesToInclude);
        IQueryable<TEntity> Where(Expression<Func<TEntity, bool>> filter);
        IQueryable<TEntity> Where(Expression<Func<TEntity, bool>> filter, string[] propertiesToInclude);

        #region Insert
        #region Sync
        /// <summary>
        /// 插入单个实体
        /// </summary>
        /// <typeparam name="T">泛型类型</typeparam>
        /// <param name="entity">要插入的实体</param>
        /// <param name="saveChanges">是否保存更改</param>
        /// <returns>返回受影响行数</returns>
        int Insert(TEntity entity, bool saveChanges = true);

        /// <summary>
        /// 插入多个实体
        /// </summary>
        /// <typeparam name="T">泛型类型</typeparam>
        /// <param name="entities">要插入的实体集合</param>
        /// <param name="saveChanges">是否保存更改</param>
        /// <returns>返回受影响行数</returns>
        int Insert(IEnumerable<TEntity> entities, bool saveChanges = true);

        /// <summary>
        /// 插入多个实体
        /// </summary>
        /// <typeparam name="T">泛型类型</typeparam>
        /// <param name="entities">要插入的实体集合</param>
        /// <param name="saveChanges">是否保存更改</param>
        /// <returns>返回受影响行数</returns>
        int Insert(List<TEntity> entities, bool saveChanges = true);
        #endregion

        #region Async
        /// <summary>
        /// 插入单个实体
        /// </summary>
        /// <typeparam name="T">泛型类型</typeparam>
        /// <param name="entity">要插入的实体</param>
        /// <param name="saveChanges">是否保存更改</param>
        /// <returns>返回受影响行数</returns>
        Task<int> InsertAsync(TEntity entity, bool saveChanges = true);

        /// <summary>
        /// 插入多个实体
        /// </summary>
        /// <typeparam name="T">泛型类型</typeparam>
        /// <param name="entities">要插入的实体集合</param>
        /// <param name="saveChanges">是否保存更改</param>
        /// <returns>返回受影响行数</returns>
        Task<int> InsertAsync(IEnumerable<TEntity> entities, bool saveChanges = true);

        /// <summary>
        /// 插入多个实体
        /// </summary>
        /// <typeparam name="T">泛型类型</typeparam>
        /// <param name="entities">要插入的实体集合</param>
        /// <param name="saveChanges">是否保存更改</param>
        /// <returns>返回受影响行数</returns>
        Task<int> InsertAsync(List<TEntity> entities, bool saveChanges = true);
        #endregion
        #endregion

        #region Delete
        #region Sync
        /// <summary>
        /// 删除全部
        /// </summary>
        /// <typeparam name="T">泛型类型</typeparam>
        /// <param name="saveChanges">是否保存更改</param>
        /// <returns>返回受影响行数</returns>
        int Delete(bool saveChanges = true);

        /// <summary>
        /// 删除单个实体
        /// </summary>
        /// <typeparam name="T">泛型类型</typeparam>
        /// <param name="entity">要删除的实体</param>
        /// <param name="saveChanges">是否保存更改</param>
        /// <returns>返回受影响行数</returns>
        int Delete(TEntity entity, bool saveChanges = true);

        /// <summary>
        /// 删除多个实体
        /// </summary>
        /// <typeparam name="T">泛型类型</typeparam>
        /// <param name="entities">要删除的实体集合</param>
        /// <param name="saveChanges">是否保存更改</param>
        /// <returns>返回受影响行数</returns>
        int Delete(IEnumerable<TEntity> entities, bool saveChanges = true);

        /// <summary>
        /// 删除多个实体
        /// </summary>
        /// <typeparam name="T">泛型类型</typeparam>
        /// <param name="entities">要删除的实体集合</param>
        /// <param name="saveChanges">是否保存更改</param>
        /// <returns>返回受影响行数</returns>
        int Delete(List<TEntity> entities, bool saveChanges = true);

        /// <summary>
        /// 根据条件删除实体
        /// </summary>
        /// <typeparam name="T">泛型类型</typeparam>
        /// <param name="predicate">条件</param>
        /// <param name="saveChanges">是否保存更改</param>
        /// <returns>返回受影响行数</returns>
        int Delete(Expression<Func<TEntity, bool>> predicate, bool saveChanges = true);

        /// <summary>
        /// 根据主键删除实体
        /// </summary>
        /// <typeparam name="T">泛型类型</typeparam>
        /// <param name="saveChanges">是否保存更改</param>
        /// <param name="KeyValues">主键值</param>
        /// <returns>返回受影响行数</returns>
        int Delete(bool saveChanges = true, params object[] KeyValues);
        #endregion

        #region Async
        /// <summary>
        /// 删除全部
        /// </summary>
        /// <typeparam name="T">泛型类型</typeparam>
        /// <param name="saveChanges">是否保存更改</param>
        /// <returns>返回受影响行数</returns>
        Task<int> DeleteAsync(bool saveChanges = true);

        /// <summary>
        /// 删除单个实体
        /// </summary>
        /// <typeparam name="T">泛型类型</typeparam>
        /// <param name="entity">要删除的实体</param>
        /// <param name="saveChanges">是否保存更改</param>
        /// <returns>返回受影响行数</returns>
        Task<int> DeleteAsync(TEntity entity, bool saveChanges = true);

        /// <summary>
        /// 删除多个实体
        /// </summary>
        /// <typeparam name="T">泛型类型</typeparam>
        /// <param name="entities">要删除的实体集合</param>
        /// <param name="saveChanges">是否保存更改</param>
        /// <returns>返回受影响行数</returns>
        Task<int> DeleteAsync(IEnumerable<TEntity> entities, bool saveChanges = true);

        /// <summary>
        /// 删除多个实体
        /// </summary>
        /// <typeparam name="T">泛型类型</typeparam>
        /// <param name="entities">要删除的实体集合</param>
        /// <param name="saveChanges">是否保存更改</param>
        /// <returns>返回受影响行数</returns>
        Task<int> DeleteAsync(List<TEntity> entities, bool saveChanges = true);

        /// <summary>
        /// 根据条件删除实体
        /// </summary>
        /// <typeparam name="T">泛型类型</typeparam>
        /// <param name="predicate">条件</param>
        /// <param name="saveChanges">是否保存更改</param>
        /// <returns>返回受影响行数</returns>
        Task<int> DeleteAsync(Expression<Func<TEntity, bool>> predicate, bool saveChanges = true);

        /// <summary>
        /// 根据主键删除实体
        /// </summary>
        /// <typeparam name="T">泛型类型</typeparam>
        /// <param name="KeyValues">主键值</param>
        /// <param name="saveChanges">是否保存更改</param>
        /// <returns>返回受影响行数</returns>
        Task<int> DeleteAsync(bool saveChanges = true, params object[] KeyValues) ;
        #endregion
        #endregion

        #region Update
        #region Sync
        /// <summary>
        /// 更新单个实体
        /// </summary>
        /// <typeparam name="T">泛型类型</typeparam>
        /// <param name="entity">要更新的实体</param>
        /// <param name="saveChanges">是否保存更改</param>
        /// <returns>返回受影响行数</returns>
        int Update(TEntity entity, bool saveChanges = true);

        /// <summary>
        /// 更新多个实体
        /// </summary>
        /// <typeparam name="T">泛型类型</typeparam>
        /// <param name="entities">要更新的实体集合</param>
        /// <param name="saveChanges">是否保存更改</param>
        /// <returns>返回受影响行数</returns>
        int Update(IEnumerable<TEntity> entities, bool saveChanges = true);

        /// <summary>
        /// 更新多个实体
        /// </summary>
        /// <typeparam name="T">泛型类型</typeparam>
        /// <param name="entities">要更新的实体集合</param>
        /// <param name="saveChanges">是否保存更改</param>
        /// <returns>返回受影响行数</returns>
        int Update(List<TEntity> entities, bool saveChanges = true);

        /// <summary>
        /// 根据条件更新实体
        /// </summary>
        /// <typeparam name="T">泛型类型</typeparam>
        /// <param name="predicate">条件</param>
        /// <param name="entity">要更新的实体</param>
        /// <param name="saveChanges">是否保存更改</param>
        /// <returns>返回受影响行数</returns>
        int Update(Expression<Func<TEntity, bool>> predicate, TEntity entity, bool saveChanges = true);
        #endregion

        #region Async
        /// <summary>
        /// 更新单个实体
        /// </summary>
        /// <typeparam name="T">泛型类型</typeparam>
        /// <param name="entity">要更新的实体</param>
        /// <param name="saveChanges">是否保存更改</param>
        /// <returns>返回受影响行数</returns>
        Task<int> UpdateAsync(TEntity entity, bool saveChanges = true);

        /// <summary>
        /// 更新多个实体
        /// </summary>
        /// <typeparam name="T">泛型类型</typeparam>
        /// <param name="entities">要更新的实体集合</param>
        /// <param name="saveChanges">是否保存更改</param>
        /// <returns>返回受影响行数</returns>
        Task<int> UpdateAsync(IEnumerable<TEntity> entities, bool saveChanges = true);

        /// <summary>
        /// 更新多个实体
        /// </summary>
        /// <typeparam name="T">泛型类型</typeparam>
        /// <param name="entities">要更新的实体集合</param>
        /// <param name="saveChanges">是否保存更改</param>
        /// <returns>返回受影响行数</returns>
        Task<int> UpdateAsync(List<TEntity> entities, bool saveChanges = true);

        /// <summary>
        /// 根据条件更新实体
        /// </summary>
        /// <typeparam name="T">泛型类型</typeparam>
        /// <param name="predicate">条件</param>
        /// <param name="entity">要更新的实体</param>
        /// <param name="saveChanges">是否保存更改</param>
        /// <returns>返回受影响行数</returns>
        Task<int> UpdateAsync(Expression<Func<TEntity, bool>> predicate, TEntity entity, bool saveChanges = true);
        #endregion
        #endregion
    }
}
